#pragma once

#include <json/json.h>
#include <httplib.h>
#include <stdexcept>
#include <string>

#include "DatabasePool.hpp"
#include "DBUtil.hpp"

using namespace std;
using namespace Json;
using namespace httplib;
using DatabasePool = ConnectionPool;

class ApiHandler
{
protected:
	DatabasePool& dbPool_;

	/**
     * @brief 发送JSON格式的成功响应
     * @param res HTTP响应对象
     * @param data 要返回的JSON数据
     * @param status HTTP状态码，默认200
     */
	static void sendSucess(Response& res, const Value& data, int status = 200) {
		FastWriter writer;
		res.set_content(writer.write(data), "application/json");
		res.status = status;
	}

	/**
     * @brief 发送错误响应
     * @param res HTTP响应对象
     * @param message 错误信息
     * @param status HTTP状态码，默认400
     */
	static void sendError(Response& res, const string& message, int status = 400) {
		Value error;
		error["error"] = message;
		sendSucess(res, error, status);
	}

public:
	explicit ApiHandler(DatabasePool& pool) : dbPool_(pool) {}
	// 纯虚函数 默认构造

	/**
     * @brief 解析HTTP请求体为JSON对象
     * @throws 当JSON格式非法时抛出runtime_error
     */
	static Value parseRequest(const Request& req) {
		Value root;
		CharReaderBuilder builder;
		JSONCPP_STRING errs;
		istringstream stream(req.body);

		// 错误处理一下
		if (!parseFromStream(builder, stream, &root, &errs)) 
			throw runtime_error("JSON 转换错误: " + errs);
		
		return root;
	}

	/**
     * @brief 验证必需参数是否存在
     * @param params JSON参数对象
     * @param required 必需参数列表
     * @return 是否所有必需参数都存在
     */
	static bool validateParams(const Value& params, const vector<std::string>& required) {
		for (const auto& param : required) {
			if (!params.isMember(param)) {
				return false;
			}
		}
		return true;
	}

	/**
	 * @brief 在事务中执行数据库操作
	 * @tparam Func 可调用对象类型
	 * @param func 要执行的操作函数
	 * @return func的返回类型
	 * 
	 * 函数工作流程：
	 * 1. 从连接池获取连接
	 * 2. 创建事务对象（构造函数中开始事务）
	 * 3. 执行用户操作
	 * 4. 成功则提交，失败自动回滚（RAII）
	 * 
	 * 关于lambda的说明：
	 * - 参数：接收一个Transacition&参数
	 * - 返回值：自动推导并传递用户函数的返回值
	 * - 异常：任何异常都会触发事务回滚
	 * 
	 * 修改说明：
	 * - 增加对void返回类型的特殊处理
	 * - 使用if constexpr实现编译期分支选择
	 * - 需要包含<type_traits>头文件
	 * 
	 * decltype的作用：
	 * -> decltype(func(declval<DBUtil::Transacition&>()))
	 * declval创建虚拟引用用于类型推导
	 * 整体表示"返回func的返回类型"
	 */
	template<typename Func>
	auto withTransaction(Func func) -> decltype(func(declval<DBUtil::Transaction&>())) 
	{
	    // 强化指针验证（兼容指针和对象成员）
    	if(reinterpret_cast<uintptr_t>(this) < 0x1000) {
    	    throw std::runtime_error("致命错误：非法this指针");
    	}
	
    	// 确保dbPool_有效（假设是引用成员）
    	try {
    	    if(&dbPool_ == nullptr) throw std::logic_error("dbPool_引用无效");
    	} catch(const std::exception& e) {
    	    throw std::runtime_error("数据库连接池未初始化");
    	}
		
		auto conn = dbPool_.getConnection();  // 先获取连接
    	if (!conn) throw runtime_error("获取连接失败");

		// 必须在try外部捕获Response引用！
    	// Response& res_ref = dynamic_cast<MenuHandler*>(this)->getCurrentResponse();
    	DBUtil::Transaction trans;  // 事务内部使用该连接
	    try {
			
	        // 执行用户传入的lambda函数
	        // func的签名应类似：[](DBUtil::Transacition&){...}
		
	        /* 返回值处理策略：
	         * 非void类型：捕获返回值并返回
	         * void类型：直接执行不返回
	         */
	        if constexpr (!std::is_same_v<decltype(func(trans)), void>) {
	            auto ans = func(trans);
	            if (!trans.commit()) throw runtime_error("提交事务失败: ");
	            return ans;  // 只有非void类型才会执行此return
	        } else {
	            func(trans);
	            if (!trans.commit()) throw runtime_error("提交事务失败: ");
	            // void类型无return语句
	        }
	    } 
	    catch(...) {
			// res_ref.status = 500;
	        // 如果提交事务失败 捕获到异常之后就要回滚
	        trans.rollback();
	        throw;
	    }
	}

	// 两种类型的重载
	/**
     * @brief 安全获取JSON字符串参数
     * @param params JSON参数对象
     * @param key 参数键名
     * @param defaultValue 默认值
     * @return 参数值或默认值
     */
	static string getStringParam(const Value& params, const string& key, const string& defaultValue = "") {
		return params.isMember(key) ? params[key].asString() : defaultValue;
	}
	/**
     * @brief 安全获取JSON整型参数
     * @param params JSON参数对象
     * @param key 参数键名
     * @param defaultValue 默认值
     * @return 参数值或默认值
     */
	static int getIntParam(const Value& params, const string& key, int defaultValue = 0) {
		return params.isMember(key) ? params[key].asInt() : defaultValue;
	}
};
